import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;


public class Client {

    // 文件名：
    static String VideoName = "gerenjianjie.mjpeg";

    // UI
    JFrame f = new JFrame("客户端");
    JButton setupButton = new JButton("初始化");
    JButton playButton = new JButton("播放");
    JButton pauseButton = new JButton("暂停");
    JButton tearButton = new JButton("关闭");
    JButton describeButton = new JButton("DESCRIBE消息");
    JPanel mainPanel = new JPanel();
    JPanel buttonPanel = new JPanel();
    JLabel statLabel1 = new JLabel();
    JLabel statLabel2 = new JLabel();
    JLabel statLabel3 = new JLabel();
    JLabel iconLabel = new JLabel();
    ImageIcon icon;

    // RTP 变量:
    DatagramPacket rcvdp;            // UDP
    DatagramSocket RTPsocket;        //
    static int RTP_RCV_PORT = 25000; // rtp端口

    Timer timer; // 用于从UDP套接字接收数据的定时器
    byte[] buf;  // 缓冲区用于存储从服务器收到的数据

    // RTSP 变量
    // rtsp 状态
    final static int INIT = 0;
    final static int READY = 1;
    final static int PLAYING = 2;
    static int state;            // RTSP 状态
    Socket RTSPsocket;           // send/receive RTSP
    InetAddress ServerIPAddr;

    // 输入与输出
    static BufferedReader RTSPBufferedReader;
    static BufferedWriter RTSPBufferedWriter;
    static String VideoFileName; // video
    int RTSPSeqNb = 0;           // rtsp序列号
    String RTSPid;              //  RTSP ID

    final static String CRLF = "\r\n";

    // RTCP 变量
    DatagramSocket RTCPsocket;
    static int RTCP_RCV_PORT = 19001;


    // 自定义！
    static int RTCP_PERIOD = 400;       // 发送rtcp的频率
    RtcpSender rtcpSender;

    static int MJPEG_TYPE = 26; // MJPEG

    //
    double statDataRate;        // 收到的视频数据的速率 单位字节/秒
    int statTotalBytes;         // 在一个会话中收到的总字节数
    double statStartTime;       // 按下启动键时的时间，以毫秒计,每次生成视频帧才进行计算
    double statTotalPlayTime;   // 从开始播放视频的时间，以毫秒计
    float statFractionLost;     // 自上一个数据包发送以来，发送方丢失的RTP数据包的比例
    int statCumLost;            // 丢失的数据包数量
    int statExpRtpNb;           // 会话中RTP消息的预期序列号
    int statHighSeqNb;          // 会话中收到的最高序列号


    FrameSynchronizer fsynch;   // 视频同步

    // 构造器
    public Client() {
        // Frame
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        // Buttons
        buttonPanel.setLayout(new GridLayout(1, 0));
        buttonPanel.add(setupButton);
        buttonPanel.add(playButton);
        buttonPanel.add(pauseButton);
        buttonPanel.add(tearButton);
        buttonPanel.add(describeButton);
        // 添加监听器
        setupButton.addActionListener(new setupButtonListener());
        playButton.addActionListener(new playButtonListener());
        pauseButton.addActionListener(new pauseButtonListener());
        tearButton.addActionListener(new tearButtonListener());
        describeButton.addActionListener(new describeButtonListener());

        // 视频显示
        iconLabel.setIcon(null);

        mainPanel.setLayout(null);
        mainPanel.add(iconLabel);
        mainPanel.add(buttonPanel);
        mainPanel.add(statLabel1);
        mainPanel.add(statLabel2);
        mainPanel.add(statLabel3);
        iconLabel.setBounds(0, 0, 380, 280);
        buttonPanel.setBounds(0, 280, 380, 50);
        statLabel1.setBounds(0, 330, 380, 20);
        statLabel2.setBounds(0, 350, 380, 20);
        statLabel3.setBounds(0, 370, 380, 20);

        f.getContentPane().add(mainPanel, BorderLayout.CENTER);
        f.setSize(new Dimension(400, 450));
        f.setVisible(true);

        // 定时器，主要任务，接收rtp数据
        timer = new Timer(50, new timerListener());
        timer.setInitialDelay(0);
        timer.setCoalesce(true);

        // 初始化 RTCP包 发送器
        rtcpSender = new RtcpSender(RTCP_PERIOD);

        buf = new byte[40000];// 分配内存用于接收server发送的每帧数据


        // 帧同步
        fsynch = new FrameSynchronizer(200);
    }


    public static void main(String[] argv) throws Exception {
        // 创建client对象
        Client theClient = new Client();
        // 服务器的RTSP端口和IP地址
        int RTSP_server_port = 1051;
        String ServerHost = "localhost";
        theClient.ServerIPAddr = InetAddress.getByName(ServerHost);
        VideoFileName = VideoName;

        // 建立tcp连接用来实现rtsp连接
        theClient.RTSPsocket = new Socket(theClient.ServerIPAddr, RTSP_server_port);

        // 输入与输出流
        RTSPBufferedReader = new BufferedReader(new InputStreamReader(theClient.RTSPsocket.getInputStream()));
        RTSPBufferedWriter = new BufferedWriter(new OutputStreamWriter(theClient.RTSPsocket.getOutputStream()));

        // 初始化rtsp状态
        state = INIT;
    }

    // 初始化按钮事件处理
    class setupButtonListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {

            System.out.println("Setup Button pressed !");
            if (state == INIT) {
                // 启动非阻塞的RTPsocket，用于接收数据
                try {
                    // 构建一个新的DatagramSocket，从服务器接收RTP数据包，端口为RTP_RCV_PORT
                    RTPsocket = new DatagramSocket(RTP_RCV_PORT);
                    // 用于发送QoS RTCP数据包的UDP套接字
                    RTCPsocket = new DatagramSocket();
                    // 设置套接字的TimeOut值为5ms
                    RTPsocket.setSoTimeout(5);
                } catch (SocketException se) {
                    se.printStackTrace();
                    System.out.println("Socket exception: " + se);
                    System.exit(0);
                }

                // 初始化RTSP序列号
                RTSPSeqNb = 1;

                // 向服务器发送SETUP信息
                sendRequest("SETUP");

                // 等待回应
                if (parseServerResponse() != 200)
                    System.out.println("SETUP : response 无效");
                else {
                    // 改变RTSP状态并打印新状态
                    state = READY;
                    System.out.println("RTSP 状态: READY");
                }
            }
        }
    }

    // 播放事件处理
    class playButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            System.out.println("点击播放按钮。");
            if (state == READY) {
                RTSPSeqNb++;
                sendRequest("PLAY");
                if (parseServerResponse() != 200) {
                    System.out.println("Response 无效");
                } else {
                    state = PLAYING;
                    System.out.println("RTSP 状态: PLAYING");
                    timer.start();
                    rtcpSender.startSend();
                }
            }
        }
    }

    // 暂停事件处理
    class pauseButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            System.out.println("点击暂停!");
            if (state == PLAYING) {
                // 增加RTSP序列号
                RTSPSeqNb++;

                // 向服务器发送PAUSE信息
                sendRequest("PAUSE");

                // 等待回应
                if (parseServerResponse() != 200)
                    System.out.println("Response 无效");
                else {
                    // 改变RTSP状态
                    state = READY;
                    System.out.println("RTSP 状态: READY");

                    // 停止计时器
                    timer.stop();
                    rtcpSender.stopSend();
                }
            }
        }
    }

    // 销毁事件处理
    class tearButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            System.out.println("停止按钮");
            // 增加RTSP序列号
            RTSPSeqNb++;
            // 向服务器发送TEARDOWN信息
            sendRequest("TEARDOWN");
            // 等待回应
            if (parseServerResponse() != 200)
                System.out.println("Response 无效");
            else {
                state = INIT;
                System.out.println("RTSP 状态: INIT");
                timer.stop();
                rtcpSender.stopSend();
                System.exit(0);
            }
        }
    }

    // 获取有关数据流的信息
    class describeButtonListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            System.out.println("发送：DESCRIBE");

            // 增加RTSP序列号
            RTSPSeqNb++;

            // 向服务器发送DESCRIBE信息
            sendRequest("DESCRIBE");

            // 等待回应
            if (parseServerResponse() != 200) {
                System.out.println("Response 无效");
            } else {
                System.out.println("Received response for DESCRIBE");
            }
        }
    }

    // 定时器处理程序,主要任务,接收rtp数据,循环进行
    class timerListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {

            // 构建一个DatagramPacket来接收来自UDP套接字的数据
            rcvdp = new DatagramPacket(buf, buf.length);

            try {
                // 从套接字中接收DP
                RTPsocket.receive(rcvdp);

                // 求播放总时间
                RTPpacket rtp_packet = new RTPpacket(rcvdp.getData(), rcvdp.getLength());
                int seqNb = rtp_packet.getSequenceNumber();// 序列号

                // 打印收到的RTP数据包的重要头字段
                System.out.println(" RTP  SeqNum : " + seqNb
                        + " TimeStamp " + rtp_packet.getTimestamp() + " ms, 类型: "
                        + rtp_packet.getPayloadType());

                // 打印头部比特流
                rtp_packet.printheader();

                // 从RTPpacket对象中获取有效载荷比特流payload
                int payload_length = rtp_packet.getPayloadLength();
                byte[] payload = new byte[payload_length];
                rtp_packet.getPayload(payload);

                // 从有效载荷比特流中获取图像
                Toolkit toolkit = Toolkit.getDefaultToolkit();
                fsynch.addFrame(toolkit.createImage(payload, 0, payload_length), seqNb);

                // 将图像显示为一个ImageIcon对象
                icon = new ImageIcon(fsynch.nextFrame());
                iconLabel.setIcon(icon);
            } catch (InterruptedIOException iioe) {
                System.out.println("没有数据");
            } catch (IOException ioe) {
                System.out.println("Exception : " + ioe);
            }
        }
    }

    // 发送RTCP控制数据包用于QoS反馈
    class RtcpSender implements ActionListener {

        private Timer rtcpTimer;
        int interval;

        private int numPktsExpected;        // 预期的RTP数据包的数量
        private int numPktsLost;            // 丢失的RTP数据包的数量
        private int lastHighSeqNb;      // 收到的最高序列号
        private int lastCumLost;          // 累计丢包量
        private float lastFractionLost; // 


        public RtcpSender(int interval) {
            this.interval = interval;
            rtcpTimer = new Timer(interval, this);
            rtcpTimer.setInitialDelay(0);
            rtcpTimer.setCoalesce(true);

        }

        public void run() {
            System.out.println("RtcpSender 线程 启动。");
        }

        public void actionPerformed(ActionEvent e) {


            RTCPpacket rtcp_packet = new RTCPpacket(0, 0, 0);
            int packet_length = rtcp_packet.getLength();
            byte[] packet_bits = new byte[packet_length];
            rtcp_packet.getPacket(packet_bits);

            try {
                DatagramPacket dp = new DatagramPacket(packet_bits, packet_length, ServerIPAddr, RTCP_RCV_PORT);
                RTCPsocket.send(dp);
            } catch (InterruptedIOException iioe) {
                System.out.println("客户端 rtcp发送失败");
            } catch (IOException ioe) {
                System.out.println("Exception : " + ioe);
            }
        }

        // 开始发送RTCP数据包
        public void startSend() {
            rtcpTimer.start();
        }

        // 结束发送RTCP数据包
        public void stopSend() {
            rtcpTimer.stop();
        }
    }

    // 帧同步
    class FrameSynchronizer {

        private ArrayDeque<Image> queue;
        private int bufSize;
        private int curSeqNb;
        private Image lastImage;

        public FrameSynchronizer(int bsize) {
            curSeqNb = 1;
            bufSize = bsize;
            queue = new ArrayDeque<>(bufSize);
        }

        // 根据帧的序列号进行同步
        public void addFrame(Image image, int seqNum) {
            if (seqNum < curSeqNb) {
                queue.add(lastImage);
            } else if (seqNum > curSeqNb) {
                for (int i = curSeqNb; i < seqNum; i++) {
                    queue.add(lastImage);
                }
                queue.add(image);
            } else {
                queue.add(image);
            }
        }

        // 获得下一个同步帧
        public Image nextFrame() {
            curSeqNb++;
            lastImage = queue.peekLast();
            return queue.remove();
        }
    }

    // 处理rtsp请求
    private int parseServerResponse() {
        int reply_code = 0;

        try {
            // 解析状态行并提取 reply_code
            String StatusLine = RTSPBufferedReader.readLine();
            System.out.println("RTSP Client - Received from Server:");
            System.out.println(StatusLine);

            StringTokenizer tokens = new StringTokenizer(StatusLine);
            tokens.nextToken(); // 跳过
            reply_code = Integer.parseInt(tokens.nextToken());

            // 200代码，则通过，获取下面两行
            if (reply_code == 200) {
                String SeqNumLine = RTSPBufferedReader.readLine();
                System.out.println(SeqNumLine);

                String SessionLine = RTSPBufferedReader.readLine();
                System.out.println(SessionLine);

                tokens = new StringTokenizer(SessionLine);
                String temp = tokens.nextToken();
                // 获取Session id
                if (state == INIT && temp.compareTo("Session:") == 0) {
                    RTSPid = tokens.nextToken();
                } else if (temp.compareTo("Content-Base:") == 0) {
                    // 获取Describe
                    String newLine;
                    for (int i = 0; i < 6; i++) {
                        newLine = RTSPBufferedReader.readLine();
                        System.out.println(newLine);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Exception : " + ex);
            System.exit(0);
        }

        return (reply_code);
    }

    // 发送rtsp请求
    private void sendRequest(String request_type) {
        try {
            // 使用RTSPBufferedWriter向RTSP套接字写入
            // 写入请求行
            RTSPBufferedWriter.write(request_type + " " + VideoFileName + " RTSP/1.0" + CRLF);

            // 写入CSeq行
            RTSPBufferedWriter.write("CSeq: " + RTSPSeqNb + CRLF);
            // 检查request_type是否等于 "SETUP"

            if (request_type == "SETUP") {
                RTSPBufferedWriter.write("Transport: RTP/UDP; client_port= " + RTP_RCV_PORT + CRLF);
            } else if (request_type == "DESCRIBE") {
                RTSPBufferedWriter.write("Accept: application/sdp" + CRLF);
            } else {
                // 其他情况，从RTSPid字段中写入会话行
                RTSPBufferedWriter.write("Session: " + RTSPid + CRLF);
            }

            RTSPBufferedWriter.flush();
        } catch (Exception ex) {
            System.out.println("Exception : " + ex);
            System.exit(0);
        }
    }
}
